<?php

    class Pages extends ActiveRecord {
        public $template_dir;
        public $content_url    = 'content';
        public $_custom_fields = array(); // holds custom field AR objects
        function _setup()
        {
            $this->table = DB_PREFIX.'pages';
            $this->template_dir = VIEWS.'/admin/pages/templates';
            $this->protected_fields('user_id'); 
        }
        
        function validate()
        {
            $this->validates_presence_of('title');
        }
        
        function after_validation()
        {            
            // sanitize meta information and title
            $this->kill_xss();
            
            $index_name = $this->get('index_name');
            if ( empty($index_name) )  {
                $this->set('index_name', $this->create_index_name($this->get('title')));
            } else {
                $this->set('index_name', $this->create_index_name($index_name)); // just to make sure its unique
            }
            // check for index page
            $is_new_index = $this->get('is_index');
            if ( $is_new_index )
            {
                $this->db->Execute('UPDATE `'.$this->table.'` SET is_index=0 WHERE is_index=1'); // clear out old home page
            }
            
        }
        
        function kill_xss()
        {
            // clean out any potentially bad xss     
            require VENDOR.'/htmlpurifier/HTMLPurifier.auto.php';       
            $config = HTMLPurifier_Config::createDefault();
            $config->set('Core', 'Encoding', DEFAULT_CHARSET); //replace with your encoding
            $config->set('HTML','Doctype',HTML_DOCTYPE);
            $purifier = new HTMLPurifier($config);
            foreach(array('meta_title','meta_keywords','meta_description','title') as $field)
            {                                
                $content = '';
                $content = $this->get($field);
                if(empty($content)) continue;
                $clean_html = $purifier->purify($this->get($field));
                $this->set($field,strip_tags($clean_html)) ;
            }                        
        }
        
        function after_validation_before_create()
        {
            $this->set('user_id',$_SESSION['user_id']);  
            $this->restrict_permissions = $this->get('restrict_permissions');
        }
        
        function after_validation_on_update()
        {
            # need to update URL, title/meta title in the search_index
            use_model('search_index');
            $index = new Search_Index();
            $url = $this->url();
            if ( $index->load($this->get('search_index_id')) )
            {
                $index->set('url',$url);
                if ( $title = $this->get('meta_title') )
                {
                    $index->set('title',$title);
                } else {
                    $index->set('title',$this->get('title'));
                }
                $index->save();
            }  else { // no search index yet so create one for it
                $index->set('url', $url);
                if ( $title = $this->get('meta_title') )
                {
                    $index->set('title',$title);
                } else {
                    $index->set('title',$this->get('title'));
                }
                $index->save();
                $this->set('search_index_id',$index->get('id'));
                $this->save();
            }      
            
            // clear the page caches
            $this->clear_page_list_cache();    
        }
        
        function after_validation_on_create()
        {                     
            if ( $this->restrict_permissions )
            {
                $this->page_permissions($this->get('id'),array($this->get('user_id')));
                unset($this->restrict_permissions);
            }
            
            # create new entry in the search_index table, put in url and write the search_index_id to this row
            use_model('search_index');
            $index = new Search_Index();
            $index->set('url', $this->url());
            if ( $title = $this->get('meta_title') )
            {
                $index->set('title',$title);
            } else {
                $index->set('title',$this->get('title'));
            }
            $index->save();
            $this->set('search_index_id',$index->get('id'));
            $this->save();
            
            // clear the page caches
            $this->clear_page_list_cache();
        }
        
        // returns index_name of page that is marked as index
        function get_index_page()
        {
            return $this->db->GetOne("select index_name from `{$this->table}` where is_index=1");
        }
        
        // loads page based on index name or returns false
        function load_page($index_name)
        {
            return $this->load('index_name=?', array($index_name));
        }
        
        function get_pages_as_list($exclude=false)
        {
            $not = '';
            if ($exclude) {
                $not = "where id!= $exclude";
            }
            return $this->db->GetAssoc("SELECT id, title FROM `{$this->table}` $not ORDER BY title");
        }
        
        function get_pages_for_js()
        {
            return $this->db->GetAssoc('SELECT index_name, title FROM `'.$this->table.'` ORDER BY title');
        }
        
        function after_delete()
        {
            // change parent nodes
            $this->db->Execute('UPDATE `'.$this->table.'` SET parent_id=? WHERE parent_id=?',
                              array($this->get('parent_id'),
                                    $this->get('id')));
            
            // delete parent content
            use_model('page_content');
            $c = new Page_Content();
            $c->delete_page_content($this->get('id'));
            
            // delete search index
            use_model('search_index');
            $index = new Search_Index();
            if ( $index->load($this->get('search_index_id')) )
            {
                $index->delete();
            }
            
            // delete any custom fields for this page
            $this->db->Execute('delete from pages_custom_fields where page_id=?', array($this->get('id')));
        }
        
        // returns list of templates
        function get_templates($include_snippets=false)
        {
            // read templates from system
            $folder_name = $this->template_dir;
            $folder = opendir($folder_name);
            $list = array();
            if ( $include_snippets )
            {
                $snippets_pattern = '';
            } else {
                $snippets_pattern = '/^\_/';
            }
            while ( $file = readdir($folder))
            {
                if ( $file != '.' && $file != '..' 
                     && !preg_match('/^\./',$file)
                     && !preg_match($snippets_pattern,$file)){
                    if (!is_dir( $folder_name.$file )){                                    
                        // get name of template
                        $template_data = implode('', file($folder_name.'/'.$file));
                        if ( preg_match("|Template Name:(.*)|i", $template_data, $name)){
                                $template_name =  $name[1];
                        } else {
                            $template_name = $file;
                        }
                        $list[$file] = $template_name; 
                    }
                }
            }    
            closedir( $folder) ;
            asort($list);
            return $list;
        }
        
        // returns actual code of template file
        function get_template_code($tpl)
        {
            // make tpl filename safe
            $file = $this->_template_name_to_safe($tpl);
            $path = $this->template_dir.'/'.$file;
            if ( file_exists($path) && is_readable($path) )
            {
                return file_get_contents($path);
            } else {
                return false;
            }
        }
        
        function add_template($post)
        {
            if (empty($post['template_human_name'])) {
                $this->add_error('template_human_name','Template human name is required');
                return false;
            }
            
            if (empty($post['template_file_name'])) {
                $this->add_error('template_file_name','Template file name is required');
                return false;
            }

            if (!preg_match("!^[a-z0-9_]+$!i",$post['template_file_name'])) {
                $this->add_error('template_file_name','Template file name can only contain letters, numbers and underscores.');
                return false;
            }
            
            $template_name = $this->_template_name_to_safe($post['template_file_name']);
            $template_human_name = $post['template_human_name'];
            if ($post['duplicate']) {
                if ($content = $this->get_template_code($post['duplicate_template'])) {
                    $content = preg_replace("|(Template Name: .*)|i","Template Name: $template_human_name",$content);
                }
            } else {
                $content = "<?"."php\n/*\nTemplate Name: $template_human_name\n*/\n?>";
            }
            
            return file_put_contents($this->template_dir.'/'.$template_name, $content);
        }
        
        function remove_template($file)
        {
            $file = $this->_template_name_to_safe($file);
            if (is_readable($this->template_dir.'/'.$file)) {
                return unlink($this->template_dir.'/'.$file);
            }
        }
        
        function write_to_template($post)
        {
            if ( !$this->template_is_writable($post['template_name']) ) {
                return false;
            }
            // write file to system;
            $filename = $this->_template_name_to_safe($post['template_name']);
            if ( $fh = fopen($this->template_dir.'/'.$filename,'w+'))
            {
                if ( !fwrite($fh,$post['template_code']) )
                {
                    return false;
                }
            } else {
                return false;
            }
            return true;
        }
        
        function _template_name_to_safe($tpl) 
        {
            $file = basename($tpl);
            $file = str_replace('.php','',$tpl);
            $file = strtr($file,'/\\','');
            if (!empty($file)) {
                return $file.'.php';
            } 
            return false;
        }
        
        function template_is_writable($tpl)
        {
            $template = $this->_template_name_to_safe($tpl);
            return is_writable($this->template_dir.'/'.$template);
        }
        
        function pages_to_ul($parent_id=0)
        {
            static $output;
            if(empty($output)){
                $output = "<ul>\n";
            }
            $pages   = $this->db->GetAll('SELECT 
                                            id,parent_id,title,index_name,page_url
                                          FROM 
                                            `'.$this->table.'` 
                                          WHERE parent_id=?',
                                          array($parent_id));
            // do kid check
            foreach($pages as $page){
                $output.= "<li><a href='{$page['page_url']}'>{$page['title']}</a>";
                $count = $this->db->GetOne('SELECT count(id) FROM `'.$this->table.'` WHERE parent_id=?',array($page['id']));
                if($count > 0){
                    $output .= "\n<ul>\n";
                    $this->pages_to_ul($page['id']);
                } else {
                    $output .= "</li>\n\n";   
                }
            }
            $output .= '</ul>';
            return $output;
        }
        
        function clear_page_list_cache()
        {
            require_once(VENDOR.'/cache/Lite.php');
            $options = array( 'cacheDir'=>CACHE.'/');            
            $Cache_Lite = new Cache_Lite($options);
            $Cache_Lite->remove('pages_to_ul');
            $Cache_Lite->remove('pages_to_td');
            $Cache_Lite->remove('pages_to_list_options');
        }
        
        function pages_to_ul_cached($parent_id=0)
        {
            require_once(VENDOR.'/cache/Lite.php');
            $options = array( 'cacheDir'=>CACHE.'/', 'cacheLifetime'=>86400 * 14);            
            $Cache_Lite = new Cache_Lite($options);
            if ( $output = $Cache_Lite->get('pages_to_ul') )
            {
                return $output;
            } else {
                $output = $this->pages_to_ul($parent_id);
                $Cache_Lite->save($output);
                return $output;
            }
        }
        
        function pages_to_list_options_cached($parent_id=0,$level=0)
        {
            require_once(VENDOR.'/cache/Lite.php');
            $options = array( 'cacheDir'=>CACHE.'/', 'cacheLifetime'=>86400 * 14);            
            $Cache_Lite = new Cache_Lite($options);
            if ( $output = $Cache_Lite->get('pages_to_list_options') )
            {
                return $output;
            } else {
                $output = $this->pages_to_list_options($parent_id,$level);
                $Cache_Lite->save($output);
                return $output;
            }
        }
        
        function pages_to_list_options($parent_id=0,$level=0,$url=false)
        {
            static $output;
            // get current page
            $pages   = $this->db->GetAll('SELECT 
                                            id,parent_id,title,index_name,page_url
                                          FROM 
                                            `'.$this->table.'` 
                                          WHERE parent_id=?',
                                          array($parent_id));
            // do kid check
            foreach($pages as $page){
                if($url)
                {
                    $output.= "<option value='{$page['page_url']}'>".
                                str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;',$level).
                              "{$page['title']}</option>";
                } else {
                    $output.= "<option value='{$page['id']}'>".
                                str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;',$level).
                              "{$page['title']}</option>";
                }
                
                $count = $this->db->GetOne('SELECT count(id) FROM `'.$this->table.'` WHERE parent_id=?',array($page['id']));
                if($count > 0){
                    $this->pages_to_list_options($page['id'],$level+1,$url);
                }
            }
            return $output;
        }
        
        function pages_to_td($parent_id=0,$level=0)
        {
            static $output;
            static $_path;
            $_path = get_installed_path();
            // get current page
            $pages   = $this->db->GetAll('SELECT 
                                            id,parent_id,title,index_name,is_index,page_url
                                          FROM 
                                            `'.$this->table.'` 
                                          WHERE parent_id=?',
                                          array($parent_id));
            // do kid check
            foreach($pages as $page){
                $view_form =    form_tag('index').
                                "<input type='hidden' name='pages[id]' value='{$page['id']}'>
                                <input type='submit' name='submit' value='Edit' class='submit'>
                                </form>";
                $delete_form = form_tag('delete').
                                "<input type='hidden' name='action' value='delete'>
                                <input type='hidden' name='id' value='{$page['id']}'>
                                <input type='submit' name='submit' value='Delete' class='submit_delete' 
                                onclick=\"return delete_confirm('row-{$page['id']}')\">
                                </form>";    
                if($page['is_index'])       
                {
                    $icon = 'page_red_text.png';
                } else {
                    $icon = 'page_white_text.png';
                }
                $output .= '<tr id="row-'.$page['id'].'">
                            <td width="1%">'.$page['id'].'</td>
                            <td>'.str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;',$level).
                            ($page['parent_id'] != 0 ? '<img src="'.$_path.'/images/admin/cat_marker.gif"/>' : ' ').
                            ' <img src="'.$_path.'/images/admin/'.$icon.'"/> '.
                            link_to($page['title'], array('controller'=>'admin/pages',
                                                    'action'=>'index?pages%5Bid%5D='.$page['id'])).
                           '</td>
                           <td width="1%"><a href="'.$page['page_url'].'" target="_blank">View&nbsp;&rarr;&nbsp;</a></td>
                           <td width="1%">'.$view_form.'</td>
                           <td width="1%">'.$delete_form.'</td>
                           </tr>';
                $count = $this->db->GetOne('SELECT count(id) FROM `'.$this->table.'` WHERE parent_id=?',
                                          array($page['id']));
                if($count > 0){
                    $this->pages_to_td($page['id'],$level+1);
                }
            }
            return $output;
        }
        
        // just returns ALL pages, really only used in the admin interface.
        function pages_to_td_cached($parent_id=0,$level=0)
        {
            require_once(VENDOR.'/cache/Lite.php');
            $options = array( 'cacheDir'=>CACHE.'/', 'cacheLifetime'=>86400 * 14);            
            $Cache_Lite = new Cache_Lite($options);
            if ( $output = $Cache_Lite->get('pages_to_td') )
            {
                return $output;
            } else {
                $output = $this->pages_to_td($parent_id,$level);
                $Cache_Lite->save($output);
                return $output;
            }
        }
        
        function get_page_users($page_id)
        {
            return $this->db->GetAssoc("SELECT 
                                          u.id, concat(u.first_name,' ',u.last_name) 
                                        FROM
                                          `".DB_PREFIX."pages_users` p, 
                                          `".DB_PREFIX."users` u
                                        WHERE
                                         p.page_id =?
                                        AND
                                         u.id = p.user_id",array($page_id));
        }
        
        function page_permissions($page_id,$users=array())
        {
            if ( $page_id > 0 )
            {
                $this->db->Execute('DELETE FROM `'.DB_PREFIX.'pages_users` WHERE page_id=?',array($page_id));
                $this->db->Execute('UPDATE `'.$this->table.'` SET has_permissions=0 WHERE id=?',array($page_id));
                if ( count($users) > 0 )
                {
                    foreach( $users as $user )
                    {
                        $this->db->Execute('INSERT INTO `'.DB_PREFIX.'pages_users` (page_id,user_id) values (?,?)',
                                            array($page_id,$user));
                    }
                    // update the 
                    $this->db->Execute('UPDATE '.$this->table.' SET has_permissions=1 WHERE id=?',array($page_id));
                }
                return true;
            } else {
                return false;
            }
        }
        
        function update_search_index_with_content()
        {
            if ( !$this->is_loaded()) return;
            use_model('search_index');
            $index = new Search_Index();
            if ( $index->load($this->get('search_index_id')) )
            {
                // get all content 
                $content = '';
                $rs      = $this->db->Execute('SELECT content FROM `'.DB_PREFIX.'page_content` WHERE page_id=?',array($this->get('id')));
                while ( !$rs->EOF )
                {
                    $content .= $rs->fields['content'];
                    $rs->MoveNext();
                }
                $index->set('content',$index->prepare_content_for_search_index($content));
                $index->save();
            }
        }
        
        // validate url structure against db, if it validates
        // then return the page to load, otherwise return false.
        function validate_url($url_sections)
        {
            $qmarks = rtrim(str_repeat("?,", (count($url_sections))),",");
            // get the url structure out of the db            
            $rs = $this->db->Execute("select id,parent_id,index_name 
                                      from `{$this->table}` 
                                      where index_name in($qmarks)",
                                      $url_sections);
            if (!$rs) {
                return false;
            }
            
            // flip the array to get the indices
            $flipped = array_flip($url_sections);
            $compare = array();
            while (!$rs->EOF) {
                $the_index = $rs->fields['index_name'];
                $the_key   = $flipped[$the_index];
                $compare[$the_key] = $rs->fields;
                $rs->MoveNext();
            }
            
            // start from the end of the array and check parent_ids on the way
            $reversed = array_reverse($compare);
            $count = count($url_sections);
                    
            for ($i=0; $i < $count; $i++) { 
                $r = $reversed[$i]['parent_id'];
                $next_index = $i + 1;
                if ($next_index == $count) {
                    if($reversed[$i]['parent_id'] != 0)
                        return false; // last element should have parent_id = 0
                                      // or its not a root element
                    break;
                }
                $c = $reversed[$next_index]['id'];
                if ($r != $c) {
                    return false;
                    break;
                }
            }
            
            return end($url_sections);
        }
        
        // determine url to currently loaded page
        function url()
        {
            $url = $this->get('page_url');
            if ($url) {
                return $url;
            }
            $path = $this->_recurse_up($this->get('parent_id'));
            $url = get_installed_path().'/'.$this->content_url;
            if(count($path) > 0) {
                $url .= '/'.implode("/",array_reverse($path));
            }            
            $url .= '/'.$this->get('index_name');
            $this->db->Execute("update `{$this->table}` set page_url=? where id=?",
                                array($url, $this->get('id')));
            return $url;
        }
        
        function _recurse_up($parent_id,$path=array())
        {
            $page = $this->db->GetRow("select id,parent_id,index_name from `{$this->table}` where id=?",
                                    array($parent_id));
               if($page){                                                     
                   $path[$page['id']] = $page['index_name'];
                   if($page['parent_id'] != 0){
                       $path = $this->_recurse_up($page['parent_id'],$path);
                   }
               }
               return $path;
        }
        
        function has_children()
        {
            return $this->find('parent_id=? order by display_order',array($this->get('id')));
        }
        
        function reorder_pages($pages)
        {
            if ( !empty($pages) )
            {
                foreach( $pages as $order => $id )
                {
                    $this->db->Execute('update pages set display_order=? where id=?',
                                        array((int)$order, (int)$id));
                }
            }
        }
        
        function related_pages()
        {
            return $this->db->GetAssoc('select rp.related_page_id, p.title 
                                        from related_pages rp, pages p
                                        where rp.page_id = ? 
                                        AND p.id = rp.related_page_id
                                        ORDER BY p.display_order',
                                        array($this->get('id')));
        }
        
        function reverse_related_pages()
        {
            return $this->db->GetAssoc('select rp.page_id, p.title 
                                        from related_pages rp, pages p
                                        where rp.related_page_id = ? 
                                        AND p.id = rp.page_id
                                        ORDER BY p.display_order',
                                        array($this->get('id')));
        }
        
        function &custom_fields()
        {
            if (!empty($this->_custom_fields)) {
                return $this->_custom_fields;
            }
            use_model('entries_custom_fields');
            $c = new entries_custom_fields();
            $cf = $c->find('page_id=?', array($this->get('id')));
            if ($cf) {
                $this->_custom_fields = $cf;
                return $cf;
            } else {
                return false;
            }
        }
        
        function &custom_field($field_key)
        {
            if (array_key_exists($field_key, $this->_custom_fields) 
                && is_object($this->_custom_fields[$field_key])) {
                return $this->_custom_fields[$field_key];
            }
            use_model('entries_custom_fields');
            $cfid = $this->db->GetOne('select id from custom_fields where field_key = ?', $field_key);
            if ($cfid) {
                $c = new entries_custom_fields();
                $cf = $c->find('page_id=? and custom_field_id=?', 
                                array($this->get('id'), $cfid));
                if ($cf) {
                    $this->_custom_fields[$field_key] = $cf;
                    return $cf;
                }
                return false;
            }
            return false;            
        }
        
    }

?>